#!/usr/bin/python
# sends packets formerly recordered
import socket, time
from optparse import OptionParser
try:
    import cjson # preferred
except:
    try:
        import json # 2.6 but no cjson
    except:
        import simplejson as json # <2.6, at least simplejson
    class cjson(object):
        decode = staticmethod(json.loads)
        encode = staticmethod(json.dumps)

usage = "usage: %prog [options] recordfile"
parser = OptionParser(usage=usage)
parser.add_option("-v", "--verbose", 
                  dest="verbose", default=False, action="store_true", 
                  help="show packets sent")
parser.add_option("-r", "--packet-rate", 
                  dest="pps", default="0", type="int",
                  help="ignore recorded time_stamp, " + 
                  "use fixed number of packages per second.\n" + 
                  "default value (0) means use recorded time stamps")
parser.add_option("-t", "--target-host", 
                  dest="target_host", default="localhost", 
                  help="where to send packets to")
parser.add_option("-p", "--port", 
                  dest="port", default=9617, type="int", 
                  help="send packets to port, default 9617")
parser.add_option("-o", "--offset", 
                  dest="offset", type="float", default=0.0, 
                  help="skip first seconds, 0.0 default")
parser.add_option("-d", "--duration", 
                  dest="duration", type="float", default=0.0, 
                  help="max. duration in seconds, 0.0 (default) EOF")


def send_packet(sock, packet):
    "send one packet to socket sock"
    jpacket = cjson.encode(packet) 
    sock.sendto(jpacket + "\n", (options.target_host, int(options.port)))

def send_packets(sock, packets):
    "send number packets at ~rate packets per second, 0 rate max speed"
    sleep_time = 1./options.pps if options.pps != 0 else 0
    last_timestamp = time.time()
    start_time = packets[0]["timestamp"]
    end_time = packets[-1]["timestamp"]+1
    if options.duration > 0:
        end_time = start_time + options.duration + options.offset
    try:
        for packet in packets:
            timestamp = packet["timestamp"]
            diff = timestamp - last_timestamp
            last_timestamp = timestamp
            if timestamp-start_time < options.offset:
                continue
            if sleep_time: # fixed pps
                time.sleep(sleep_time)
            else: # as recorded (is always with timestamp)
                if diff > 0.001: # not below millisecond
                    time.sleep(diff)
            if timestamp > end_time:
                break
            if options.verbose:
                print packet
            send_packet(sock, packet)
    except KeyboardInterrupt:
        print "Keyboard interrupt, ending"


def main(packets):
    "connection surrounding packet sending"
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP socket
    send_packets(sock, packets)
    sock.close()

if __name__ == '__main__':
    options, args = parser.parse_args()
    if len(args) != 1:
        parser.error("must be exactly one filename")
    try:
        dics = [cjson.decode(line) for line in file(args[0]) if line.strip()]
    except Exception, e:
        print "problem reading packets, file problem or format problem"
    main(dics)
